<?php
require_once 'OAuth/OAuth.php';
require "doubanoauth/config.php";
	
class douban implements IService{
	const REQUEST_TOKEN_URL = 'http://www.douban.com/service/auth/request_token';
	const ACCESS_TOKEN_URL = 'http://www.douban.com/service/auth/access_token';
	const AUTHORIZATION_URL = 'http://www.douban.com/service/auth/authorize';
	const SERVICE_NAME='Douban';
	const NAME = 'Douban';
	
	protected $_server = 'http://www.douban.com';
	protected $_consumer = NULL;
	protected $_token = NULL;
	protected $_method = NULL;
	
	public $accessToken = NULL;
	public $accessTokenSecret = NULL;
	//public $key = API_KEY;
	//public $secret = API_SECRET;
	
	public function reconstruct($key = NULL, $secret = NULL, $server = 'http://www.douban.com')
	{
		$this->_server = $server;
		$this->_consumer =  new OAuthConsumer($key, $secret);	
		$this->_method = new OAuthSignatureMethod_HMAC_SHA1();
	}

	public function __construct($AccessToken = NULL, $AccessTokenSecret = NULL){
		if (!isset($AccessToken)|| !isset($AccessTokenSecret)){
			$this->reconstruct(API_KEY,API_SECRET);
		}else{
			$this->accessToken = $AccessToken;
			$this->accessTokenSecret = $AccessTokenSecret;
			$this->reconstruct(API_KEY,API_SECRET);
		}
	}
	
	public function getRequestToken()
	{
		$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, NULL, 'GET', self::REQUEST_TOKEN_URL);
		$oauthRequest->sign_request($this->_method, $this->_consumer, NULL);
		return $this->fetchToken($oauthRequest);
	}
	
	public function parse($content = NULL) 
	{
		$arr = explode("&", $content);
		$size = sizeof($arr);
		$result = array();
		if ($size == 2) {
			$token = explode("=", $arr[1]);
			$secret = explode("=", $arr[0]);
			$result["oauth_token"] = $token[1];
			$result["oauth_token_secret"] = $secret[1];
			$result["douban_user_id"] = NULL;
		} else if ($size == 3) {
			$token = explode("=", $arr[1]);
			$secret = explode("=", $arr[0]);
			$user = explode("=", $arr[2]);
			$result["oauth_token"] = $token[1];
			$result["oauth_token_secret"] = $secret[1];
			$result["douban_user_id"] = $user[1];
		}
		return $result;
	}
	
	
	public function fetchToken($oauthRequest = NULL){
		$ci = curl_init();
		$header = $oauthRequest->to_header(" ");
		Yii::trace($header);
		//print_r($header);
		curl_setopt($ci, CURLOPT_HEADER,FALSE);
	    curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
	    //print_r($oauthRequest->to_header());
	    //curl_setopt($ci, CURLOPT_HTTPHEADER, array());
	    curl_setopt($ci, CURLOPT_URL, $oauthRequest->get_normalized_http_url());
	    
	    //curl_setopt($ci, CURLOPT_POST, TRUE);
	    //curl_setopt($ci,CURLOPT_POSTFIELDS, $header);
	    curl_setopt($ci, CURLOPT_HTTPHEADER, array('Content-Type: application/atom+xml', $header));

	    $response = curl_exec($ci);
	    //var_dump($response);
	    //Yii::trace($response);
	    $re = $this->parse($response);
	    //var_dump($re);
	    return $re;
	}
	
	public function getAuthorizationUrl($key = NULL, $secret = NULL, $callback = NULL)
	{
		$parameters = array();
		$parameters["oauth_token"] = $key;
 		if ($callback) {
			$parameters["oauth_callback"] = $callback;
			$oauthRequest = new OAuthRequest('GET', self::AUTHORIZATION_URL, $parameters);
		} else {
			$oauthRequest = new OAuthRequest('GET', self::AUTHORIZATION_URL, $parameters);
		}
		return $oauthRequest->to_url();
	}
		
	public static function register($param1=NULL,$param2 = NULL){
		$connection = new douban();
		$requestToken = $connection->getRequestToken();
		$key = $requestToken["oauth_token"];
		$secret = $requestToken["oauth_token_secret"];
		$_SESSION['oauth_token'] = $key;
		$_SESSION['oauth_token_secret'] = $secret;
		if (!$key) {
			print 'get request token failed';
  			return false;
		}	
		$url = $connection->getAuthorizationUrl($key,$secret,CALLBACK_URL);
		//echo $url;
		Header('Location:'.$url);
		
	}

	public static function loginSecond(){
		$connection = new douban();
		$key = $_SESSION['oauth_token'];
		$secret = $_SESSION['oauth_token_secret'];
		$token = $connection->getAccessToken($key, $secret);
		//echo $key.' '.$secret;
      	$_SESSION['access_token'] = $token["oauth_token"];
      	$_SESSION['access_token_secret'] = $token["oauth_token_secret"];
      	$_SESSION['douban_user_id'] = $token['douban_user_id'];
		//print_r($token);
		$connection->accessToken = $key;	//应该是把accessToken和secret都存进数据库，这里是测试代码
		$connection->accessTokenSecret = $secret;
		$_SESSION['verified'] = 1;
	}
	
	public function getAccessToken($key = NULL, $secret = NULL, $token = NULL)
	{
		if ($key && $secret) {
			$token = new OAuthToken($key, $secret);
		}
		$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, $token, 'GET', self::ACCESS_TOKEN_URL);
		$oauthRequest->sign_request($this->_method, $this->_consumer, $token);
		return $this->fetchToken($oauthRequest);
	}
	
	public function getUserInfo($paraments = NULL){
		$key = $this->accessToken;
		$secret = $this->accessTokenSecret;
		$url = 'http://api.douban.com/people/'.urlencode('@me');
		$token = new OAuthToken($key, $secret);
		$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, $token, 'GET', $url);//测试代码
		$oauthRequest->sign_request($this->_method, $this->_consumer, $token);
		return $this->get($oauthRequest);
	}
	
	public function getFriendsTimeline($max=20, $start=1){
		$userID = $this->getID();
		//echo $userID.'<br />';
		$key = $this->accessToken;
		$secret = $this->accessTokenSecret;
		$token = new OAuthToken($key, $secret);
		$baseurl = $userID.'/miniblog/contacts';
		$url = $baseurl.'?start-index='.$start.'&max-results='.$max;
		//echo $url;
		$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, $token, 'GET', $url);//测试代码
		$oauthRequest->sign_request($this->_method, $this->_consumer, $token);
		$cont = $this->get($oauthRequest);
		//var_dump($cont);
		Yii::trace($cont);
		return $cont;
	}
	
	
	public function getUpdateEntry($content){
		$string = '<?xml version=\'1.0\' encoding=\'UTF-8\'?>'.
		'<entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/"><content>'.
		$content.'</content></entry>';
		echo $string;
		return $string;
	}
	
	public function getID(){
		$con = $this->getUserInfo();
		//var_dump($con);
		$xml = @simplexml_load_string($con);
		$url = $xml->id;
		//echo $url;
		return $url;
	}
	
	/**
	 * 发布一条信息（Tweet，状态等）。发送失败即抛出异常throw new Exception('xxx update failed.');
	 * 
	 * @param string $target 消息发出去的目标 
	 * @param unknown_type $content
	 * 
	 */
	public function update($content){
		$key = $this->accessToken;
		$secret = $this->accessTokenSecret;
		$token = new OAuthToken($key, $secret);
		//$baseurl = 'http://api.douban.com/people/'.$userID.'/miniblog';
		$url = 'http://api.douban.com/miniblog/saying';
		$content = $this->getUpdateEntry($content);
		$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, $token, 'POST', $url);//测试代码
		$oauthRequest->sign_request($this->_method, $this->_consumer, $token);
		$re = $this->post($oauthRequest,$content);
		if(!isset($re)){
			throw new Exception($content.' update failed.');
		}
		
	}
	
	public function post($oauthRequest, $content){
		$ci = curl_init();
		$header = $oauthRequest->to_header(" ");
	    curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
	    curl_setopt($ci, CURLOPT_URL, $oauthRequest->get_normalized_http_url());
	    //curl_setopt($ci, CURLOPT_HTTPHEADER, array($oauthRequest->to_header(), $oauthRequest->getString()));
	    curl_setopt($ci, CURLOPT_HTTPHEADER, array($header,'Content-Type: application/atom+xml; charset=UTF-8'));
	    //echo $postfields;
	    curl_setopt($ci, CURLOPT_POST, TRUE);
        curl_setopt($ci, CURLOPT_POSTFIELDS, $content);
	    curl_setopt($ci, CURLOPT_HEADER,FALSE);
	    $response = curl_exec($ci);
	    //var_dump($response);
	    return $response;
	}
	


	public function get($oauthRequest){
		$ci = curl_init();
		$header = $oauthRequest->to_header(" ");
	    curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
	    curl_setopt($ci, CURLOPT_URL, $oauthRequest->to_url());
	    //curl_setopt($ci, CURLOPT_HTTPHEADER, array($oauthRequest->to_header(), $oauthRequest->getString()));
	    curl_setopt($ci, CURLOPT_HTTPHEADER, array($header));
	    
	    curl_setopt($ci, CURLOPT_HEADER,FALSE);
	    $response = curl_exec($ci);
	    //var_dump($response);
	    return $response;
		
	}

	/**
	 * 获取当前用户在该服务上的Timeline内容（Tweets、新鲜事、广播等）。更新失败即抛出异常throw new Exception('xxx failed.')
	 * 
	 * @param int $count 每次返回的消息数，默认为10条
	 * @param int $page 返回第几页的内容
	 * 
	 * @return 一个包含了最新消息的二维数组，每条信息的数组元素定义如下：
	 *         array(
	 *               'uid'=>该user在该服务中的ID,
	 *               'id'=>该条信息在相应服务中的ID,
	 *               'source'=>'消息来源服务的代号',
	 *               'user'=>'用户名',
	 *               'avatar'=>'头像URL',
	 *               'content'=>消息正文内容,
	 *               'datetime'=>发布时间，格式为Unix时间戳（长整型）， 请参考strtotime函数
	 *         )
	 */
	public function getLatest($count = 10, $page = 0){
		$start = $count*$page+1;
		$string =  $this->getFriendsTimeline($count,$start);
		Yii::trace($string);
		$xml = @simplexml_load_string($string);
		//var_dump($xml);
		//echo $xml->entry[1]->content;
		$re = array();
		for ($i = 0; $i<$count;$i++){

				
			$item = array(
			'uid'=>$xml->entry[$i]->author->uri,
			'id'=>$xml->entry[$i]->id,
			'source'=>'Douban',
			'user'=>$xml->entry[$i]->author->name,
			'content'=>$xml->entry[$i]->content,
			'datetime'=>strtotime(substr($xml->entry[$i]->published,0,19))
			);
			
			if( $xml->entry[$i]->author->link[2]!=NULL){
				$ava = $xml->entry[$i]->author->link[2]->attributes();
				$item['avatar']=$ava['href'];
			}else 
				$item['avatar'] = 'http://img3.douban.com/icon/user_normal.jpg';
				$re[$i] = $item;
		}
		return $re;
	}



	/**
	 * 回复一条消息。发送失败即抛出异常throw new Exception('xxx update failed.');
	 * 
	 * 这个方法在实现的时候要首先判断一下自己是否是相应的$target，不是就直接返回FALSE。例如：
	 * if ($target != self::name) return FALSE;
	 * 
	 * @param string $target 目标服务的代号（用于判断是否处理，见update方法说明）
	 * @param int $id 回复的消息ID
	 * @param string $content 回复的正文，如果相应的服务对字数有限制，需要做截断处理
	 * @param int $reply_to 回复给某人的UID（可选，似乎只有人人中用得到）
	 * 
	 * @return bool 消息回复是否成功
	 */
	

	public function reply($target, $id, $content, $reply_to = null){
		
	}

	/**
	 * 获取单一用户的资料和更新消息。更新失败即抛出异常throw new Exception('xxx failed.');
	 * 
	 * @param string $target 目标服务的代号（用于判断是否处理，见reply方法说明）
	 * @param int $uid 用户在目标服务中的ID
	 * 
	 * @return 一个数组，定义如下：
	 *         array(
	 *             'profile'=>array(//一个数组，包含了一些有用的个人资料，必须要有的是名字、头像信息，其他的自由考虑，例如BIO、生日之类的
	 *                             'username'=>'用户名',
	 *                             'avatar'=>'头像URL（可以是稍微大一点的头像图片）'
	 *                        ),
	 *             'timeline'=>array(//包含了该特定用户最近的10条更新，格式和getLatest方法返回值相同
	 *                         )
	 *         )
	 */
	public function getProfile($target, $uid){
		if($target!=self::SERVICE_NAME) return false;
		else{
			$key = $this->accessToken;
			$secret = $this->accessTokenSecret;
			$url = $uid;
			$token = new OAuthToken($key, $secret);
			$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, $token, 'GET', $url);//测试代码
			$oauthRequest->sign_request($this->_method, $this->_consumer, $token);
			
			$string = $this->get($oauthRequest);
			//var_dump($string);
			Yii::trace(print_r($string,true));
			$xml = @simplexml_load_string($string);
			$ava = $xml->link[2]->attributes();
			$profile =array(
			'username'=>$xml->title,
			'avatar'=>$ava['href']
			);
			//var_dump($profile);
			$cont = $this->getUserTimeline($uid);
			//var_dump($cont);
			$xml = @simplexml_load_string($cont);
			//var_dump($xml);
			$timeline = array();
			for ($i = 0; $i<10;$i++){
				
				
				
				$item = array(
							'uid'=>$xml->author->uri,
							'id'=>$xml->entry[$i]->id,
							'source'=>'Douban',
							'user'=>$xml->author->name,
							'content'=>$xml->entry[$i]->content,
							'datetime'=>strtotime(substr($xml->entry[$i]->published,0,19))
							);
			if( $xml->entry[$i]->author->link[2]!=NULL){
				$ava = $xml->entry[$i]->author->link[2]->attributes();
				$item['avatar']=$ava['href'];
			}else 
				$item['avatar'] = 'http://img3.douban.com/icon/user_normal.jpg';
				$re[$i] = $item;
				$timeline[$i] = $item;
				//var_dump($item);
			}
			$re = array('profile'=>$profile, 'timeline'=>$timeline);
			//var_dump($re);
			return $re;
		}
	}
	
	function getUserTimeline($uid){

		//echo $userID.'<br />';
		$key = $this->accessToken;
		$secret = $this->accessTokenSecret;
		$token = new OAuthToken($key, $secret);
		$baseurl = $uid.'/miniblog';
		$url = $baseurl.'?start-index=1&max-results=10';
		//echo $url;
		$oauthRequest = OAuthRequest::from_consumer_and_token($this->_consumer, $token, 'GET', $url);//测试代码
		$oauthRequest->sign_request($this->_method, $this->_consumer, $token);
		$cont = $this->get($oauthRequest);
		//var_dump($cont);
		return $cont;
	}
	
	function getMyName(){
		$info = $this->getProfile(self::NAME, 'http://api.douban.com/people/%40me');
		//var_dump($info);
		return $info['profile']['username'];
	}
	
	function getMyID(){
		$info = $this->getProfile(self::NAME, 'http://api.douban.com/people/%40me');
		
		$t = $info['timeline'];
		//var_dump($t);
		return $t[1]['uid'];
	}
}
/*
session_start();

if (isset($_GET['oauth_token'])){
	douban::loginSecond();
	//echo $_SESSION['verified'];
	header('Location:'.CONTROLLER_FILE);
}*/
?>